<template>
  <div class="Triassic">
    <div
      ref="canvas"
      class="Player"
      v-loading="loading"
      :element-loading-text="`模型加载${process}%，请稍等`"
    >
      <el-drawer
        title="三叠纪恐龙"
        center
        :show-close="false"
        :visible.sync="drawer1"
        direction="ltr"
        :modal-append-to-body="false"
      >
        <div class="models">
          <el-card
            :body-style="{ padding: '0px' }"
            v-for="(model, index) in modelList"
            :key="index"
            shadow="always"
          >
            <img
              :src="`${$public.ip}/DinosaurModelPicture/${model.modelPicture}`"
              class="image"
            />
            <div style="padding: 14px">
              <span>{{ model.chineseName }}</span>
              <div class="bottom clearfix">
                <el-button
                  type="text"
                  class="button"
                  @click="toggle(model.chineseName)"
                  >点击切换</el-button
                >
              </div>
            </div>
          </el-card>
        </div>
      </el-drawer>
      <el-drawer
        title="三叠纪恐龙"
        center
        :show-close="false"
        :visible.sync="drawer2"
        direction="rtl"
        :modal-append-to-body="false"
      >
        <img :src="introducePicture" alt="" class="image" />

        <div class="text">{{ introduce }}</div>
      </el-drawer>
      <div class="more" @click="openBox" style="z-index: 99">
        <div>查看更多</div>
        <img src="../images/icons/right.png" alt="" />
      </div>
      <div class="knowlege" @click="openBox2" style="z-index: 99">
        <img src="../images/icons/left.png" alt="" />
        <div>查看资料</div>
      </div>
    </div>

    <div class="GUI" v-show="groupID" ref="GUI">
      <el-button @click="rotate3D" size="mini">旋转360</el-button>
      <el-button @click="handlerStop" size="mini">暂停旋转</el-button>
      <el-button @click="handlerGo" size="mini">继续旋转</el-button>
      <el-button @click="handlerFront" size="mini">正视图</el-button>
      <el-button @click="handlerSide" size="mini">侧视图</el-button>
      <el-button @click="handlerAxes" size="mini">{{
        `坐标系(${GUI.status.axesHelper == true ? "开" : "关"})`
      }}</el-button>
      <el-button @click="returns" size="mini">回到首页</el-button>
    </div>
  </div>
</template>

<script>
//api
import { getDinosaurbyName, getDinosaurs, getModel } from "@/api/api";
import gsap from "gsap";
import { Message } from "element-ui";
import _ from "lodash";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
let [scene, camera, renderer, loader] = [null, null, null, null];
export default {
  name: "TriassicModels",
  data() {
    return {
      process: 0, //进度
      drawer1: false, //更多模型开关
      drawer2: false, //查看资料开关
      modelList: [], //模型数据列表
      modelUrl: "", //加载模型的地址
      introducePicture: "", //加载模型的图片
      introduce: "", //加载模型的资料
      groupID: "", //加载模型的场景内容标识
      basicID: "",
      loading: true, //加载开关
      GUI: {
        status: {
          rotate: false,
          axesHelper: false,
        },
        rotateTime: 5,
      },
      timeline: {
        rotateTimeLine: null,
      },
    };
  },
  async mounted() {
    //搭建3D场景
    this.init3D();
    //播放时间线
    this.timeline.rotateTimeLine = gsap.timeline();
    //获取三叠纪数据
    let res = await getDinosaurs("三叠纪");
    this.modelList = res.data;
    //处理数据
    if (this.modelList.length > 0) {
      //如果有数据
      //判断页面是否有查询参数
      if (this.$route.params.hasOwnProperty("name")) {
        //有参数,则获取参数恐龙
        let result = await getDinosaurbyName(this.$route.params.name);
        //更新内容
        Message.success({
          message: `获取模型${this.$route.params.name}`,
        });
        this.updateData(result);
      } else {
        //无参数，则获取第一个模型
        let result = await getDinosaurbyName(this.modelList[0].chineseName);
        console.log(result);
        //更新内容
        Message.success({
          message: `获取模型${this.modelList[0].chineseName}`,
        });
        this.updateData(result);
        //加载第一个次模型
        this.loadModel();
      }
    } else {
      this.loading = false;
      Message.warning({
        message: `暂无数据`,
      });
    }
  },
  methods: {
    //初始化
    init3D() {
      //搭建场景
      scene = new THREE.Scene();
      //搭建相机
      camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        2000
      );
      //摆放相机位置
      camera.position.set(400, 0, 0);
      camera.lookAt(0, 0, 0);
      const basic = new THREE.Group();
      this.basicID = basic.uuid;
      basic.add(camera);
      //向场景中添加相机 (电影开机)
      scene.add(basic);
      //渲染环境

      new RGBELoader().setPath("hdr/").load("hdr.hdr", (texture) => {
        //环境反射效果
        texture.mapping = THREE.EquirectangularReflectionMapping;
        scene.background = texture;
        scene.environment = texture;
      });

      //初始化渲染器{ antialias抗锯齿 }
      renderer = new THREE.WebGLRenderer({ antialias: true });

      //设置渲染的尺寸大小
      renderer.setSize(window.innerWidth, window.innerHeight);

      //添加canvas画布到盒子里
      this.$refs.canvas.appendChild(renderer.domElement);

      //创建轨道控制器
      const controls = new OrbitControls(camera, renderer.domElement);
      //开启阻尼
      controls.enableDamping = true;
      //构建渲染函数
      let render = () => {
        controls.update();
        //如果存在renderer
        if (renderer) {
          renderer.render(scene, camera, true);
          requestAnimationFrame(render);
        }
      };
      if (renderer) {
        render();
      }
      //监听画面变化，更新渲染画面
      window.addEventListener("resize", () => {
        if (camera) {
          //更新相机宽高比
          camera.aspect = window.innerWidth / window.innerHeight;
          //更新相机的投影矩阵
          camera.updateProjectionMatrix();
        }
        if (renderer) {
          //更新渲染器(画布大小)
          renderer.setSize(window.innerWidth, window.innerHeight);
          //设置渲染器的像素比例
          renderer.setPixelRatio(window.devicePixelRatio);
        }
      });

      //创建GLEF模型加载器
      loader = new GLTFLoader();
    },
    //加载模型
    loadModel: _.debounce(function () {
      loader.load(
        this.modelUrl,
        (gltf) => {
          const group = gltf.scene;
          this.toSceneCenter(group);
          this.groupID = group.uuid;
          gsap.fromTo(
            this.$refs.GUI,
            {
              y: "-100%",
            },
            {
              y: 0,
              duration: 1,
            }
          );
          if (scene) {
            scene.add(group);
          }
        },
        ({ loaded, total }) => {
          this.process = ((loaded / total) * 100).toFixed(2);
          console.log(loaded, total);
          if (loaded == total) {
            console.log(1);
            this.loading = false;
          }
        }
      );
    }, 2000),
    async hasData() {
      if (this.modelList.length > 0) {
        return true;
      }
      return false;
    },
    //移除模型
    removeModel() {
      scene.children.forEach((element) => {
        if (element.uuid == this.groupID) {
          scene.remove(element);
        }
      });
    },
    //切换模型
    async toggle(modelName) {
      this.process = 0;
      this.drawer1 = false;
      this.loading = true;
      this.removeModel();
      let result = await getDinosaurbyName(modelName);
      console.log("切换模型" + modelName);
      this.updateData(result);
      //切换模型
      this.loadModel();
    },
    // 获取模型最小包围盒数据
    getBoxInfo(mesh) {
      const box3 = new THREE.Box3();
      box3.expandByObject(mesh);
      const size = new THREE.Vector3();
      const center = new THREE.Vector3();
      // 获取包围盒的中心点和尺寸
      box3.getCenter(center);
      box3.getSize(size);
      return {
        size,
        center,
      };
    },
    //缩放后固定在世界中心
    toSceneCenter(mesh) {
      const { center, size } = this.getBoxInfo(mesh);
      // 将Y轴置为0
      let scaleValue = 0;
      let sizeArr = size.toArray();
      //计算最大缩放比例
      for (let i = 0; i < sizeArr.length; i++) {
        for (let j = 0; j < sizeArr.length; j++) {
          if (sizeArr[i] >= sizeArr[j]) {
            scaleValue = 300 / sizeArr[i];
          }
        }
      }
      console.log(size);

      //缩放
      mesh.scale.set(scaleValue, scaleValue, scaleValue);
      //设置模型位置，将包围盒中心和世界中心重合
      mesh.position.set(
        -center.x * scaleValue,
        -center.y * scaleValue,
        -center.z * scaleValue
      );
    },
    //更新数据
    updateData(result) {
      this.GUI.status.rotate = false;
      const [url, picture, introduce] = [
        result.data.modelUrl,
        result.data.introducePicture,
        result.data.introduce,
      ];
      this.modelUrl = `${this.$public.ip}/DinosaurModels/${url}`;
      this.introducePicture = `${this.$public.ip}/DinosaurIntroducePicture/${picture}`;
      this.introduce = introduce;
    },
    //查看更多模型
    openBox() {
      this.drawer1 = true;
    },
    //查看资料
    openBox2() {
      this.drawer2 = true;
    },
    //回到首页
    returns() {
      this.$router.replace({
        name: "Home",
      });
    },
    //释放内存
    dispose() {
      scene.traverse((child) => {
        if (child.material) {
          child.material.dispose();
        }
        if (child.geometry) {
          child.geometry.dispose();
        }
        child = null;
      });
      camera = null; // 释放相机对象
      renderer.dispose(); // 销毁渲染器对象
    },
    //旋转
    rotate3D() {
      //找出模型
      console.log(this.GUI.status.rotate);
      //如果未开启
      if (!this.GUI.status.rotate) {
        //旋转开启
        this.GUI.status.rotate = true;
        //新建时间线
        this.createNewTimeline();
        //旋转
        scene.children.forEach((Obj3D) => {
          if (Obj3D.uuid == this.groupID) {
            this.timeline.rotateTimeLine.to(Obj3D.rotation, {
              y: Math.PI * 2,
              duration: this.GUI.rotateTime,
              repeat: -1,
              ease: "none",
            });
          }
        });
      } else {
        //如果开启
        this.timeline.rotateTimeLine.resume();
      }
    },
    handlerFront() {
      this.createNewTimeline();
      this.GUI.status.rotate = false;
      scene.children.forEach((Obj3D) => {
        if (Obj3D.uuid == this.groupID) {
          gsap.to(Obj3D.rotation, {
            y: 0,
            duration: 2,
            ease: "none",
          });
        }
      });
      gsap.to(camera.position, {
        z: 400,
        x: 0,
        y: 0,
        duration: 2,
        ease: "none",
      });
    },
    handlerSide() {
      this.createNewTimeline();
      this.GUI.status.rotate = false;

      scene.children.forEach((Obj3D) => {
        if (Obj3D.uuid == this.groupID) {
          gsap.to(Obj3D.rotation, {
            y: 0,
            duration: 2,
            ease: "none",
          });
        }
      });
      gsap.to(camera.position, {
        x: 400,
        y: 0,
        z: 0,
        duration: 2,
        ease: "none",
      });
    },
    handlerStop() {
      this.timeline.rotateTimeLine.pause();
    },
    handlerGo() {
      this.timeline.rotateTimeLine.resume();
    },
    handlerAxes() {
      this.GUI.status.axesHelper = !this.GUI.status.axesHelper;
      if (this.GUI.status.axesHelper) {
        const axesHelper = new THREE.AxesHelper(300);
        scene.children.forEach((item) => {
          if (item.uuid == this.basicID) {
            item.add(axesHelper);
          }
        });
      } else {
        scene.children.forEach((item) => {
          if (item.uuid == this.basicID) {
            item.children.forEach((group) => {
              if (group.type == "AxesHelper") {
                item.remove(group);
              }
            });
          }
        });
      }
    },

    createNewTimeline() {
      this.timeline.rotateTimeLine.kill();
      this.timeline.rotateTimeLine = null;
      this.timeline.rotateTimeLine = gsap.timeline();
    },
  },
  beforeDestroy() {
    //释放内存
    this.dispose();
  },
  destroyed() {
    //清空
    scene = null;
    camera = null;
    renderer = null;
  },
};
</script>

<style scoped>
.Triassic {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.models {
  color: red;
}
.item {
  margin: 10px 0;
  text-align: center;
  color: #fff;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
  position: relative;
  border: 10px #ccc solid;
}

.more {
  position: fixed;
  width: 60px;
  height: 100vh;
  left: 0px;
  top: 0;
  background-color: rgba(255, 255, 255, 0.6);
  text-align: center;
  display: flex;
  align-items: center;
  color: #409eff;
  cursor: pointer;
}
.knowlege {
  position: fixed;
  width: 60px;
  height: 100vh;
  right: 0;
  top: 0;
  background-color: rgba(255, 255, 255, 0.6);
  text-align: center;
  display: flex;
  align-items: center;
  color: #409eff;

  cursor: pointer;
}
.more > img,
.knowlege > img {
  width: 30px;
  height: 30px;
}
.image {
  width: 100%;
}
.text {
  font-size: 20px;
  text-indent: 2em;
  padding: 10px;
  text-align: justify;
}

.modelPicture {
  width: 100%;
  position: relative;
  z-index: 0;
  display: block;
}
.name {
  position: relative;
  bottom: 0;
  left: 0;
  width: 100%;
  text-align: center;
  z-index: 5;
}

.models {
  height: 100%;
  overflow-y: auto;
}
.models::-webkit-scrollbar {
  width: 8px;
}
.models::-webkit-scrollbar-track {
  background-color: #ccc;
}
.models::-webkit-scrollbar-thumb {
  background-color: #409eff;
  border-radius: 4px;
}
</style>

<style>
.el-drawer__body::-webkit-scrollbar {
  width: 8px;
}
.el-drawer__body::-webkit-scrollbar-track {
  background-color: #ccc;
}
.el-drawer__body::-webkit-scrollbar-thumb {
  background-color: #409eff;
  border-radius: 4px;
}

.GUI {
  position: absolute;
  top: 0;
  left: 60px;
  background: rgba(255, 255, 255, 0.5);
  display: flex;
  padding: 5px 10px;
}
</style>
